const {task, src, dest, series, parallel} = require('gulp')
const rename = require('gulp-rename')
const concat = require('gulp-concat')
const replace = require('gulp-replace')
const clean = require('gulp-clean')
const through = require('through2')
const fs = require('fs')
const _ = require('lodash')
const {sep} = require('path')
require('dotenv-flow').config()


const cwd = './src';
const error_java_content = fs.readFileSync('./ErrorCodeConstants.java')
const error_java_template = _.template(error_java_content)
const module_name = process.env.TOOLS_MODULE_NAME
const main_name = process.env.TOOLS_MAIN_NAME
const error_start = process.env.TOOLS_ERROR_START
const menu_sql_name = module_name + '-menu.sql'
const base_path = `./codegen-${module_name}*`
const java_test_sql_path = `${main_name}-module-${module_name}/${main_name}-module-${module_name}-biz/src/test/resources/sql/`;
const java_api_err_path = `${main_name}-module-${module_name}/${main_name}-module-${module_name}-api/src/main/java/com/${main_name}/module/${module_name}/enums`

task('mixin:dir', () => src(`${base_path}/**/*`, {ignore: [`${base_path}/**/*.sql`, `${base_path}/**/ErrorCodeConstants_手动操作.java`], cwd})
	.pipe(rename((path) => {
		path.dirname = path.dirname.split(sep).slice(1).join(sep)
	}))
	.pipe(dest('./dist/'))
)

task('mixin:menu', () => src(`${base_path}/sql/sql.sql`, {cwd})
	.pipe(concat(menu_sql_name))
	.pipe(dest('./dist/sql/mysql/menus/'))
)

task('mixin:error', () => {
	let i = 0;
	const map = {};
	return src(`${base_path}/**/ErrorCodeConstants_手动操作.java`, {cwd})
		.pipe(replace(/\/\/\sTODO\s.*\n/, ''))
		.pipe(replace(/TODO 补充编号/g, function(_, _, text) {
			map[text] = map[text] || i++;
			return error_start * 1 +  map[text] * 1000;
		}))
		.pipe(concat({path: 'ErrorCodeConstants.java'}))
		.pipe(rename((path) => {
			path.dirname = java_api_err_path;
		}))
		.pipe(through.obj((file, enc, cb) => {

		    // ignore empty files
		    if (file.isNull()) {
		      cb();
		      return;
		    }

		    // we don't do streams (yet)
		    if (file.isStream()) {
		      this.emit('error', new Error('gulp-concat: Streaming not supported'));
		      cb();
		      return;
		    }
		    const lines = file.contents.toString().split('\n');

		    const result = error_java_template({
	    		content: lines.join('\n    '),
	    		main_name,
	    		module_name
	    	});

	    	file.contents = Buffer.from(result)

		    cb(null, file);
		}))
		.pipe(dest('./dist/'))
}
)

task('mixin:test:create', () => {
	return src(`${base_path}/sql/h2.sql`, {cwd})
		.pipe(through.obj((file, enc, cb) => {

		    // ignore empty files
		    if (file.isNull()) {
		      cb();
		      return;
		    }

		    // we don't do streams (yet)
		    if (file.isStream()) {
		      this.emit('error', new Error('gulp-concat: Streaming not supported'));
		      cb();
		      return;
		    }
		    const lines = file.contents.toString().split('\n\n');

	    	file.contents = Buffer.from(lines[0])

		    cb(null, file);
		}))
		.pipe(concat('create.sql', {newLine: '\n\n'}))
		.pipe(dest('./dist/' + java_test_sql_path))
})

task('mixin:test:clean', () => {
	return src(`${base_path}/sql/h2.sql`, {cwd})
		.pipe(through.obj((file, enc, cb) => {

		    // ignore empty files
		    if (file.isNull()) {
		      cb();
		      return;
		    }

		    // we don't do streams (yet)
		    if (file.isStream()) {
		      this.emit('error', new Error('gulp-concat: Streaming not supported'));
		      cb();
		      return;
		    }
		    const lines = file.contents.toString().split('\n\n');

	    	file.contents = Buffer.from(lines[1])

		    cb(null, file);
		}))
		.pipe(concat('clean.sql'))
		.pipe(dest('./dist/' + java_test_sql_path))
})

task('clean', () => {
	if (fs.existsSync('./dist')) {
		return src('./dist').pipe(clean())
	}
	return Promise.resolve(0)
})

const javaClasses = ['BigDecimal', 'LocalDateTime', 'LocalTime', 'LocalDate'];
const javaClassFullPathes = {
	BigDecimal: 'java.math.BigDecimal',
	LocalTime: 'java.time.LocalTime',
	LocalDate: 'java.time.LocalDate',
	LocalDateTime: 'java.time.LocalDateTime'
};

task('check:java', () => src(`./dist/**/*.java`, {})
	.pipe(through.obj((file, enc, cb) => {

	    // ignore empty files
	    if (file.isNull()) {
	      cb();
	      return;
	    }

	    // we don't do streams (yet)
	    if (file.isStream()) {
	      this.emit('error', new Error('gulp-concat: Streaming not supported'));
	      console.log(1)
	      cb();
	      return;
	    }
	    let contents = file.contents.toString();
	    const needClass = [];

		for (const javaClass  of javaClasses) {
			if (contents.indexOf(javaClass) >= 0 && contents.indexOf(javaClassFullPathes[javaClass] + ';') < 0) {
				needClass.push(javaClassFullPathes[javaClass])
			}
		}
		contents = contents.split('\n')
		if (needClass.length !== 0) {
			contents.splice(2, 0, needClass.map((path) => 'import ' + path + ';').join('\n'))
		}
		const imports = []
		for(let i = contents.length - 1; i >= 0; i-- ){
			const importJavaClass = contents[i].trim();
			if (importJavaClass.startsWith('import')) {
				if (imports.indexOf(importJavaClass) >= 0) {
					contents.splice(i, 1);
					continue;
				}
				imports.push(importJavaClass);
			}
		}

    	file.contents = Buffer.from(contents.join('\n'))

	    cb(null, file);
	}))
	.pipe(dest('./dist/'))
)

task('default', series('clean', parallel('mixin:dir', 'mixin:menu', 'mixin:test:create', 'mixin:test:clean', 'mixin:error'), 'check:java'))



